<#
.SYNOPSIS
	Return the SnapMirror status. This command can be issued on either the source 
    or destination filer.
.DESCRIPTION
	Return the SnapMirror status. This command can be issued on either the source 
    or destination filer.
.PARAMETER Location
  	The source location or destination location of the SnapMirror pair. Possible 
    types are volume or qtree only. If this input is provided, only the SnapMirror 
    relationships with a matching source or destination will be reported.  If the 
    argument is not specified, all source, destination SnapMirror pairs are returned. 
.PARAMETER Server
   	NaServer to query
.EXAMPLE
  	Get-Navol Vol1 | Get-NaSnapshot
    
    Get any snapmirrors associated with vol1
.Example
    Get-NaSnapshot -location netapp1:/vol/vol1/qsm
    
    Get any QSM at /vol/vol1/qsm
.OUTPUTS
	NetApp.SDK.NaSnapMirrorStatus[]
.Link
	Set-NaSnapMirror
	Initialize-NaSnapMirror
	Update-NaSnapMirror
	Remove-NaSnapMirror
	Restore-NaSnapMirror
	Get-NaSnapMirrorSchedule
	Set-NaSnapMirrorSchedule
	Enable-NaSnapMirror
	Disable-NaSnapMirror
#> 
function Get-NaSnapMirror {
	[CmdletBinding(SupportsShouldProcess=$FALSE,SupportsTransactions=$False,ConfirmImpact="None",DefaultParameterSetName="")]
	param(
	[Parameter(Position=0,ValueFromPipelineByPropertyName=$TRUE)]
	[alias("volume","Source")]
	[string]
	$location,

	[Parameter(Position=1,HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-get-status")
		if ($location){
			$request.AddNewChild("location",$location)
		}
		try {
			$result = ([xml]$server.InvokeElem($request)).results
		}
		catch [NetApp.Manage.NaApiFailedException]{
			Write-Warning $_.Exception.GetBaseException().message
			$result = $null
			continue;
		}
		if ($? -and (ConvertFrom-NaBool $result."is-available")) {
			$result."snapmirror-status"."snapmirror-status-info" |
			Where-Object {$_."source-location"} | % {
				return New-Object NetApp.SDK.NaSnapMirrorStatus -ArgumentList @(
				$_."source-location",
				$_."destination-location",
				$_."status",
				$_."state",
				[timespan]::FromSeconds($_."lag-time"),
				(ConvertFrom-NaTime $_."mirror-timestamp"),
				$_."base-snapshot",
				$_."contents",
				$_."transfer-progress",
				$_."current-transfer-type",
				$_."last-transfer-size",
				[timespan]::FromSeconds($_."last-transfer-duration"),
				$_."last-transfer-type"
				)
			}
		}
		else {
			write-warning "Snapmirror Unavailiable"
		}
	}
}
<#
.SYNOPSIS
	Starts an initial transfer over the network for a specific destination. This 
    cmdlet must be issued to the destination filer.
.DESCRIPTION
	Starts an initial transfer over the network for a specific destination. This 
    cmdlet must be issued to the destination filer.
.PARAMETER Abort
	Cancels any transfer for a destination. This cmdlet can be issued from either 
	the source or destination filer.
.PARAMETER ClearCheckpoint
	If provided then the restart checkpoint is cleared.
.PARAMETER Break
	Breaks a snapmirrored relationship. No checking on whether the operation is 
	legal, or whether it is successful. I.e. you need to query status afterward by 
	using Get-NaSnapmirror cmdlet.
.PARAMETER Quiesce
	Pauses transfers to the destination. The status of the path must be checked 
	to discover when the path is quiesced.
.PARAMETER Resume
	Resumes transfers to the destination that were quiesced.
.PARAMETER MaxTransferRate
	Changes the max transfer rate of an active transfer. Maximum transfer rate in 
	kilobytes per second. A value '0' disables the throttle, ie. the filer will 
	transfer as fast as it can.
.PARAMETER Server
   	NaServer to query
.EXAMPLE
	Get-NaSnapMirror vol1 | Set-NaSnapMirror -Abort
	Abort any active snapmirror transfers on vol1.
.EXAMPLE
	Get-NaSnapMirror vol1 | Set-NaSnapMirror -Break
	Break the snapmirror relationship on vol1.
.EXAMPLE
	Get-NaSnapMirror vol1 | Set-NaSnapMirror -Quiesce
	Quiesce all IO on the vol1 snapmirror.
.EXAMPLE
	Get-NaSnapMirror vol1 | Set-NaSnapMirror -Resume
	Resume a previously aborted snapmirror transfer on vol1.
.EXAMPLE
	Get-NaSnapMirror vol1 | Set-NaSnapMirror -Release
	Release vol1 from any snapmirror relationships, must be ran on source!
.OUTPUTS
	NetApp.SDK.NaSnapMirrorStatus[]
.Link
	Get-NaSnapMirror
	Initialize-NaSnapMirror
	Update-NaSnapMirror
	Remove-NaSnapMirror
	Restore-NaSnapMirror
#> 
function Set-NaSnapMirror {
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="Low",DefaultParameterSetName="")]
	param(
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName='Abort')]
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName='Break')]
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName='Quiesce')]
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName='Resume')]
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName='Release')]
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName='throttle')]
	[alias("volume")]
	[string]
	$Destination,

	[Parameter(Mandatory=$TRUE,ParameterSetName='Abort')]
	[switch]
	$Abort,

	[Parameter(Mandatory=$false,ParameterSetName='Abort')]
	[switch]
	$ClearCheckpoint,

	[Parameter(Mandatory=$TRUE,ParameterSetName='Break')]
	[switch]
	$Break,

	[Parameter(Mandatory=$TRUE,ParameterSetName='Quiesce')]
	[switch]
	$Quiesce,

	[Parameter(Mandatory=$TRUE,ParameterSetName='Resume')]
	[switch]
	$Resume,

	[Parameter(Mandatory=$TRUE,Position=1,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="Release")]
	[string]
	$Source,

	[Parameter(Mandatory=$TRUE,ParameterSetName='Release')]
	[switch]
	$Release,

	[Parameter(Mandatory=$TRUE,Position=1,ParameterSetName='throttle')]
	[int]
	$MaxTransferRate,

	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		switch ($PSCmdlet.ParameterSetName)
		{
			'Abort'
			{
				$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-abort")
				if ($ClearCheckpoint) {
					$request.AddNewChild("clear-checkpoint",$true)
				}
				$msg = "Cancelling Snapmirror transfer $($Destination)"
			} 
			'Break'
			{
				$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-break")
				$msg = "Breaking Snapmirror $($Destination)"
			}
			'Quiesce'
			{
				$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-quiesce")
				$msg = "Quiesce Snapmirror $($Destination)"
			}
			'Resume'
			{
				$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-resume")
				$msg = "Resume Snapmirror transfer $($Destination)"
			}
			'Release'
			{
				$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-release")
				$request.AddNewChild("source-location", $Source)
				$msg = "Releasing $($Destination) from $($Source)"
			}
			'throttle'
			{
				$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-throttle")
				$request.AddNewChild("max-transfer-rate",$MaxTransferRate)
				$msg = "Setting the max transfer rate on $($Destination) to $($MaxTransferRate) Kbs"
			}

		}
		$request.AddNewChild("destination-location",$Destination)
		if ($pscmdlet.ShouldProcess($Server.Server,$msg)){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
			if ($?){
				Get-NaSnapMirror -location $Destination -Server $Server
			}
		}
	}
}
<#
.SYNOPSIS
	Enables SnapMirror data transfers and turns on the SnapMirror scheduler. 
.DESCRIPTION
	Enables SnapMirror data transfers and turns on the SnapMirror scheduler.  
.PARAMETER Server
   	NaServer to query
.EXAMPLE
	Enable-NaSnapMirror
.Link
	Disable-NaSnapMirror	
#> 
function Enable-NaSnapMirror {
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="Low",DefaultParameterSetName="")]
	param(
	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		if ($pscmdlet.ShouldProcess($Server.Server,"Enable SnapMirror")){
			try {
				$server.Invoke("snapmirror-on") | out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
		}
	}
}
<#
.SYNOPSIS
	Disables SnapMirror data transfers and turns off the SnapMirror scheduler. 
.DESCRIPTION
	Disables SnapMirror data transfers and turns off the SnapMirror scheduler. 
.PARAMETER Server
   	NaServer to query
.EXAMPLE
	Enable-NaSnapMirror
.Link
	Get-NaSnapMirror
	Disable-NaSnapMirror	
#> 
function Disable-NaSnapMirror {
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="Low",DefaultParameterSetName="")]
	param(
	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		if ($pscmdlet.ShouldProcess($Server.Server,"Disable SnapMirror")){
			try {
				$server.Invoke("snapmirror-off") | out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
		}
	}
}
<#
.SYNOPSIS
	Starts an initial transfer over the network for a specific destination. This 
    cmdlet must be issued to the destination filer.
.DESCRIPTION
	Starts an initial transfer over the network for a specific destination. This 
    cmdlet must be issued to the destination filer.
.PARAMETER Destination
    The destination location of the initial transfer. The destination location is 
    of the volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>. 
    The <filer> must match the destination filer. If the destination is in the 
    volume form, the volume must be in the restricted state. If the destination 
    is the qtree form, the qtree must not already exist. 
.PARAMETER Source
    The source location of the initial transfer. The source location is of the 
    volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>. 
    If the source-location is not specified, then the source in /etc/snapmirror.conf 
    for the destination path is used. 
.PARAMETER DestinationSnapshot
    Creates the specified snapshot (in addition to the regular SnapMirror snapshot) 
    on the destination after the qtree SnapMirror transfer is over. 
.PARAMETER SourceSnapshot
    Designates which source snapshot to use for a qtree update. The default creates 
    new snapshot on the source for the transfer. 
.PARAMETER MaxTransferRate
    Maximum transfer rate in kilobytes per second. The default is as fast as the 
    filer can transfer. 
.PARAMETER Server
   	NaServer to query
.EXAMPLE
    Get-NaSnapMirror | ?{$_.State -eq "uninitialized"}| Initialize-NaSnapMirror
    
    Initilize any uninitilize snapmirror targets
.Example
    Initialize-NaSnapMirror -Destination sm_vol1
    
    Initilize the snapmirror relationship for vm_vol1
.OUTPUTS
	NetApp.SDK.NaSnapMirrorStatus[]
.Link
	Get-NaSnapMirror
	Set-NaSnapMirror
	Update-NaSnapMirror
	Remove-NaSnapMirror
	Restore-NaSnapMirror
	Get-NaSnapMirrorSchedule
	Set-NaSnapMirrorSchedule
#> 
function Initialize-NaSnapMirror {
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="Low",DefaultParameterSetName="")]
	param(
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE)]
	[alias("volume")]
	[string]
	$Destination,

	[Parameter(Position=1,ValueFromPipelineByPropertyName=$TRUE)]
	[string]
	$Source,

	[Parameter(ValueFromPipelineByPropertyName=$TRUE)]
	[string]
	$DestinationSnapshot,

	[Parameter(ValueFromPipelineByPropertyName=$TRUE)]
	[string]
	$SourceSnapshot,

	[Parameter(ValueFromPipelineByPropertyName=$TRUE)]
	[int]
	$MaxTransferRate,

	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-initialize")
		$request.AddNewChild("destination-location",$Destination)
		if ($Source){
			$request.AddNewChild("source-location",$Source)
		}
		if ($DestinationSnapshot){
			$request.AddNewChild("destination-snapshot",$DestinationSnapshot)
		}
		if ($SourceSnapshot){
			$request.AddNewChild("source-snapshot",$SourceSnapshot)
		}
		if ($MaxTransferRate){
			$request.AddNewChild("max-transfer-rate",$MaxTransferRate)
		}
		if ($pscmdlet.ShouldProcess($Server.Server,"initializing $($Destination) SnapMirror")){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
			if ($?){
				Get-NaSnapMirror -location $Destination -Server $Server
			}
		}
	}
}
<#
.SYNOPSIS
	Starts a transfer over the network for a specific destination. The update is 
	asynchronously handled, and there is no guarantee that it succeeds. 
.DESCRIPTION
	Starts a transfer over the network for a specific destination. The update is 
	asynchronously handled, and there is no guarantee that it succeeds. This 
    cmdlet must be issued to the destination filer.
.PARAMETER Destination
    The destination location of the update transfer. The destination location is 
    of the volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>. 
    The <filer> must match the destination filer. If the destination is in the 
    volume form, the volume must be in the restricted state. If the destination 
    is the qtree form, the qtree must not already exist. 
.PARAMETER Source
    The source location of the update transfer. The source location is of the 
    volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>. 
    If the source-location is not specified, then the source in /etc/snapmirror.conf 
    for the destination path is used. 
.PARAMETER DestinationSnapshot
    Creates the specified snapshot (in addition to the regular SnapMirror snapshot) 
    on the destination after the qtree SnapMirror transfer is over. 
.PARAMETER SourceSnapshot
    Designates which source snapshot to use for a qtree update. The default creates 
    new snapshot on the source for the transfer. 
.PARAMETER MaxTransferRate
    Maximum transfer rate in kilobytes per second. The default is as fast as the 
    filer can transfer. 
.PARAMETER Server
   	NaServer to query
.EXAMPLE
	Get-NaSnapMirror vol1| Update-NaSnapMirror
.OUTPUTS
	NetApp.SDK.NaSnapMirrorStatus[]
.Link
	Get-NaSnapMirror
	Set-NaSnapMirror
	Initialize-NaSnapMirror
	Remove-NaSnapMirror
	Restore-NaSnapMirror
	Get-NaSnapMirrorSchedule
	Set-NaSnapMirrorSchedule
#> 
function Update-NaSnapMirror {
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="Low",DefaultParameterSetName="")]
	param(
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE)]
	[alias("volume")]
	[string]
	$Destination,

	[Parameter(Position=1,ValueFromPipelineByPropertyName=$TRUE)]
	[string]
	$Source,

	[Parameter(ValueFromPipelineByPropertyName=$TRUE)]
	[string]
	$DestinationSnapshot,

	[Parameter(ValueFromPipelineByPropertyName=$TRUE)]
	[string]
	$SourceSnapshot,

	[Parameter(ValueFromPipelineByPropertyName=$TRUE)]
	[int]
	$MaxTransferRate,

	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-update")
		$request.AddNewChild("destination-location",$Destination)
		if ($Source){
			$request.AddNewChild("source-location",$Source)
		}
		if ($DestinationSnapshot){
			$request.AddNewChild("destination-snapshot",$DestinationSnapshot)
		}
		if ($SourceSnapshot){
			$request.AddNewChild("source-snapshot",$SourceSnapshot)
		}
		if ($MaxTransferRate){
			$request.AddNewChild("max-transfer-rate",$MaxTransferRate)
		}
		if ($pscmdlet.ShouldProcess($Server.Server,"Updating $($Destination) SnapMirror")){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
			if ($?){
				Get-NaSnapMirror -location $Destination -Server $Server
			}
		}
	}
}
<#
.SYNOPSIS
	Kicks off a resync of a broken snapmirrored pair. 
.DESCRIPTION
	Kicks off a resync of a broken snapmirrored pair. The update is asynchronously 
	handled, and there is no guarantee that it succeeds. This requires that a schedule 
	in /etc/snapmirror.conf is set for the destination. The API must be issued on the 
	destination filer.
.PARAMETER Destination
    Destination location of the snapmirrored pair to break, The destination location 
	is of the volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>. 
.PARAMETER Source
    Source location of the transfer. The source location is is of the volume 
	form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>. If the 
	source-location is not specified, then the source in /etc/snapmirror.conf for the 
	destination path is used. 
.PARAMETER DestinationSnapshot
    Creates the specified snapshot (in addition to the regular SnapMirror snapshot) 
	on the destination after the qtree SnapMirror transfer is over. 
.PARAMETER SourceSnapshot
    Designates which source snapshot to use for a qtree update. If source-snapshot 
	is not specfied, a new snapshot will be created.
.PARAMETER MaxTransferRate
    Maximum transfer rate in kilobytes per second. The default is as fast as the 
    filer can transfer. 
.PARAMETER Server
   	NaServer to query
.EXAMPLE
	Get-NaSnapMirror vol1 | Restore-NaSnapMirror
	
	Restore the snapmirror relationship on vol1
.OUTPUTS
	NetApp.SDK.NaSnapMirrorStatus[]
.Link
	Get-NaSnapMirror
	Set-NaSnapMirror
	Initialize-NaSnapMirror
	Remove-NaSnapMirror
	Update-NaSnapMirror
	Get-NaSnapMirrorSchedule
	Set-NaSnapMirrorSchedule
#> 
function Restore-NaSnapMirror {
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="Low",DefaultParameterSetName="")]
	param(
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE)]
	[alias("volume")]
	[string]
	$Destination,

	[Parameter(Position=1,ValueFromPipelineByPropertyName=$TRUE)]
	[string]
	$Source,

	[Parameter(ValueFromPipelineByPropertyName=$TRUE)]
	[string]
	$DestinationSnapshot,

	[Parameter(ValueFromPipelineByPropertyName=$TRUE)]
	[string]
	$SourceSnapshot,

	[Parameter(ValueFromPipelineByPropertyName=$TRUE)]
	[int]
	$MaxTransferRate,

	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-resync")
		$request.AddNewChild("destination-location",$Destination)
		if ($Source){
			$request.AddNewChild("source-location",$Source)
		}
		if ($DestinationSnapshot){
			$request.AddNewChild("destination-snapshot",$DestinationSnapshot)
		}
		if ($SourceSnapshot){
			$request.AddNewChild("source-snapshot",$SourceSnapshot)
		}
		if ($MaxTransferRate){
			$request.AddNewChild("max-transfer-rate",$MaxTransferRate)
		}
		if ($pscmdlet.ShouldProcess($Server.Server,"Resyncing the $($Destination) SnapMirror")){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
			if ($?){
				Get-NaSnapMirror -location $Destination -Server $Server
			}
		}
	}
}

<#
.SYNOPSIS
	Returns the schedule for a given destination or all destinations. This command 
    must be executed on the destination filer.
.DESCRIPTION
	Returns the schedule for a given destination or all destinations. This command 
    must be executed on the destination filer. Currently, the schedules is in 
    /etc/snapmirror.conf.
.PARAMETER Destination
    The destination location of a schedule to obtain. The destination location is 
    of the volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>. 
    The <filer> must match the destination filer. If the Destination is 
    not specified, then all the destination schedules are returned. 
.PARAMETER Server
   	NaServer to query
.EXAMPLE
    Get-NaSnapMirrorSchedule -destination sm_vol1
    
    Get the Snapmirror update Schedule for sm_vol1
.OUTPUTS
	NetApp.SDK.NaSnapMirrorSchedule[]
.Link
	Set-NaSnapMirrorSchedule
	Get-NaSnapMirror
	Set-NaSnapMirror
	Initialize-NaSnapMirror
	Update-NaSnapMirror
#> 
function Get-NaSnapMirrorSchedule {
	[CmdletBinding(SupportsShouldProcess=$False,SupportsTransactions=$False,ConfirmImpact="Low",DefaultParameterSetName="")]
	param(
	[Parameter(Position=0,ValueFromPipelineByPropertyName=$TRUE)]
	[alias("volume")]
	[string]
	$Destination,

	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-list-schedule")
		if ($Destination){
			$request.AddNewChild("destination-location",$Destination)
		}
		try {
			$result = ([xml]$server.InvokeElem($request)).results
		}
		catch [NetApp.Manage.NaApiFailedException]{
			Write-Warning $_.Exception.GetBaseException().message
			$result = $null
			continue;
		}
		if ($?){
			$result."snapmirror-schedules"."snapmirror-schedule-info" | 
			?{$_.Source -and $_.Destination} | % {
				$SnapmirrorError = new-object Collections.Hashtable
				$_."snapmirror-error" | % {
					$SnapmirrorError.Add("errno",$_.errno)
					$SnapmirrorError.Add("reason",$_.reason)
				}
				return New-Object Netapp.SDK.NaSnapMirrorSchedule -ArgumentList @(
				$_."source-location",
				$_."destination-location",
				$_."days-of-month",
				$_."days-of-week",
				$_."minutes",
				$_."hours",
				$_."max-transfer-rate",
				$SnapmirrorError
				)
			}
		}
	}
}
<#
.SYNOPSIS
	Sets the schedule for a given destination. The API must be executed on the 
    destination filer. Currently, the schedule is in /etc/snapmirror.conf.
.DESCRIPTION
	Sets the schedule for a given destination. The API must be executed on the 
    destination filer. Currently, the schedule is in /etc/snapmirror.conf. 
.PARAMETER Destination
    The destination location of a schedule to set. The destination location is 
    of the volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>.  
.PARAMETER Source
    The destination location of a schedule to set.  The source location is of the 
    volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>. 
.PARAMETER Days
    Minutes in the hour for which the schedule is set. The form is crontab-like, 
    with possible values of:
        * - := match nothing;
        * 1 := match day 1;
        * 1,3 := match day 1 and 3;
        * 2-5 := match day 2,3,4,5;
        * 1-30/7 := match day 1,8,15,22,29;
        * * := matches all possible legal values; 
.PARAMETER WeekDays
    Days in the week for which the schedule is set. 0 represents Sunday, and 6 
    represents Saturday. The form is crontab-like, with possible values of:
        * - := match nothing;
        * 1 := match day 1 (Mon);
        * 1,3 := match day 1 and 3 (Mon and Wed);
        * 2-5 := match day 2,3,4,5 (Tue,Wed,Thu,Fri);
        * * := matches all possible legal values; 
.PARAMETER Hours
	Hours in the day for which the schedule is set. The form is crontab-like, 
    with possible values of:
        * - := match nothing;
        * 1 := match hour 1;
        * 1,3 := match hour 1 and 3;
        * 2-5 := match hour 2,3,4,5;
        * 1-24/3 := match hour 1,4,7,10,13,16,19,22;
        * * := matches all possible legal values; 
.PARAMETER Minutes
	Minutes in the hour for which the schedule is set. The form is crontab-like,
    with possible values of:
        * - := match nothing;
        * 1 := match minute 1;
        * 1,3 := match minute 1 and 3;
        * 2-5 := match minute 2,3,4,5;
        * 1-12/3 := match minute 1,4,7,10;
        * 0-55/5 := match minute 0,5,10,15,20,25,30,35,40,45,50,55;
        * * := matches all possible legal values; 
.PARAMETER Schedule
    For advanced users this parameter accepts the scedual in the format used in snapmirror.conf.
    
    example: "* 1,3,5 1-24/2 1"
    
    Will Schedule an update every Mon, Wends, and Friday, every other hour.  
.PARAMETER MaxTransferRate
    Maximum transfer rate in kilobytes per second. The default is as fast as the filer 
    can transfer. 
.PARAMETER RestartMode
    Restart mode when transfer is interrupted. Possible values are "always", "never" 
    and "restart". If value is set to "always", then an interrupted transfer will 
    always restart, if it has a restart check point and the conditions are the same 
    as before the transfer was interrupted. If value is set to "never", then an 
    interrupted transfer will never restart, even if it has a restart checkpoint. 
    If "restart" option is not specified,then it is set to "default" value; where 
    snapmirror behaves like the "always" case, unless it has passed the next scheduled 
    transfer time, in which case it will begin that scheduled transfer instead of 
    restarting. 
.PARAMETER Server
   	NaServer to query
.EXAMPLE
    Set-NaSnapMirrorSchedule -Destination sm_vol1 -Source netapp2:vol1 -Schedule "- - - -"
    
    Establish a snapmirror relationship between netapp2:vol2 and netapp1:vol1
.OUTPUTS
	NetApp.SDK.NaSnapMirrorSchedule[]
.Link
	Get-NaSnapMirrorSchedule
	Get-NaSnapMirror
	Set-NaSnapMirror
	Initialize-NaSnapMirror
	Update-NaSnapMirror
#> 
function Set-NaSnapMirrorSchedule {
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="Low",DefaultParameterSetName="byParam")]
	param(
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byParam")]
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byString")]
	[alias("volume")]
	[string]
	$Destination,

	[Parameter(Mandatory=$TRUE,Position=1,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byParam")]
	[Parameter(Mandatory=$TRUE,Position=1,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byString")]
	[string]
	$Source,

	[Parameter(ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byParam")]
	[string]
	$Days = '-',

	[Parameter(ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byParam")]
	[string]
	$WeekDays = '-',

	[Parameter(ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byParam")]
	[string]
	$Hours = '-',

	[Parameter(ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byParam")]
	[string]
	$Minutes = '-',

	[Parameter(ParameterSetName="byString")]
	[ValidatePattern('^\S+\s\S+\s\S+\s\S+$')]
	[string]
	$Schedule,

	[Parameter(ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byParam")]
	[Parameter(ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byString")]
	[int]
	$MaxTransferRate,

	[Parameter(ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byParam")]
	[Parameter(ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byString")]
	[ValidateSet("always", "never", "restart")]
	[string]
	$RestartMode,

	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		if ($Schedule) {
			$Days, $WeekDays, $Hours, $Minutes = $Schedule.Split()
		}
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-set-schedule")
		$request.AddNewChild("destination-location",$Destination)
		$request.AddNewChild("source-location",$Source)
		$request.AddNewChild("days-of-month", $Days)
		$request.AddNewChild("days-of-week",$WeekDays)
		$request.AddNewChild("hours",$Hours)
		$request.AddNewChild("minutes",$Minutes)

		if ($RestartMode){
			$request.AddNewChild("restart",$RestartMode)
		}
		if ($MaxTransferRate){
			$request.AddNewChild("max-transfer-rate",$MaxTransferRate)
		}
		if ($pscmdlet.ShouldProcess($Server.Server,"Settting $($Destination) snapmirror Schedule to $($Days, $WeekDays, $Hours, $Minutes -join " ")")){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
			if ($?){
				Get-NaSnapMirror -location $Destination -Server $Server
			}
		}
	}
}
<#
.SYNOPSIS
	Delete the schedule for a given destination. This cmdlet must be executed on the
    destination filer.
.DESCRIPTION
	Delete the schedule for a given destination. This cmdlet must be executed on the
    destination filer.
.PARAMETER Destination
	The destination location of a schedule to delete. The destination location is 
    of the volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>.
.PARAMETER Server
   	NaServer to query
.EXAMPLE
	Remove-NaSnapMirrorSchedule -Destination Netapp1:vol1
.Link
	Get-NaSnapMirrorSchedule
	Set-NaSnapMirrorSchedule
	Initialize-NaSnapMirror
	Update-NaSnapMirror
	Restore-NaSnapMirror
#> 
function Remove-NaSnapMirrorSchedule {
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="Low",DefaultParameterSetName="")]
	param(
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE)]
	[alias("volume")]
	[string]
	$Destination,

	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-delete-schedule")
		$request.AddNewChild("destination-location",$Destination)
		if ($pscmdlet.ShouldProcess($Server.Server, "Removing $($Destination) from the snapmirror Schedule")){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
		}
	}
}

<#
.SYNOPSIS
	Returns the synchronous schedule for a given destination or all destinations. This command 
    must be executed on the destination filer.
.DESCRIPTION
	Returns the schedule for a given destination or all destinations. This command 
    must be executed on the destination filer. Currently, the schedules is in 
    /etc/snapmirror.conf.
.PARAMETER Destination
    The destination location of a schedule to obtain. The destination location is 
    of the volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>. 
    The <filer> must match the destination filer. If the Destination is 
    not specified, then all the destination schedules are returned. 
.PARAMETER Server
   	NaServer to query
.EXAMPLE
    Get-NaSnapMirrorSyncSchedule -destination sm_vol1
    
    Get the Snapmirror synchronous update Schedule for sm_vol1
.OUTPUTS
	NetApp.SDK.NaSnapMirrorSyncSchedule[]
.Link
	Set-NaSnapMirrorSyncSchedule
	Get-NaSnapMirror
	Set-NaSnapMirror
	Initialize-NaSnapMirror
	Update-NaSnapMirror
#> 
function Get-NaSnapMirrorSyncSchedule {
	[CmdletBinding(SupportsShouldProcess=$False,SupportsTransactions=$False,ConfirmImpact="Low",DefaultParameterSetName="")]
	param(
	[Parameter(Position=0,ValueFromPipelineByPropertyName=$TRUE)]
	[alias("volume")]
	[string]
	$Destination,

	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-list-sync-schedule")
		if ($Destination){
			$request.AddNewChild("destination-location",$Destination)
		}
		try {
			$result = ([xml]$server.InvokeElem($request)).results
		}
		catch [NetApp.Manage.NaApiFailedException]{
			Write-Warning $_.Exception.GetBaseException().message
			$result = $null
			continue;
		}
		if ($?){
			$result."snapmirror-sync-schedules"."snapmirror-sync-schedule-info" | 
			?{$_."source-location" -and $_."destination-location"} |% {
				$SnapmirrorError = new-object Collections.Hashtable
				$_."snapmirror-error" | % {
					$SnapmirrorError.Add("errno",$_.errno)
					$SnapmirrorError.Add("reason",$_.reason)
				}
				return New-Object Netapp.SDK.NaSnapMirrorSyncSchedule -ArgumentList @(
				$_."source-location",
				$_."destination-location",
				$_."ops-throttle",
				$_."sync-mode",
				$_."visibility-frequency",
				$SnapmirrorError
				)
			}
		}
	}
}
<#
.SYNOPSIS
	Establishes a synchronous or semi-synchronous schedule. Currently, the 
	schedules are in: /etc/snapmirror.conf. Semi-synchronous mode is determined
	by specifing semi-sync.
.DESCRIPTION
	Establishes a synchronous or semi-synchronous schedule. Currently, the 
	schedules are in: /etc/snapmirror.conf. Semi-synchronous mode is determined
	by specifing semi-sync. Must be executed on the destination filer.
.PARAMETER Destination
    The destination location of a schedule to set. The destination location is 
    of the volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>.
.PARAMETER Source
    The Source location of a schedule to set.  The source location is of the 
    volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>. 
.PARAMETER VisibilityFrequency
	Controls how often the source snapspot will be visible on the destination 
	mirror. This input is used to control the value of visibility_interval in 
	the snapmirror.conf file. The units are in seconds. A typical value to use 
	for this input is 180
.PARAMETER OpsThrottle
    The number of outstanding operations allowed before blocking on the source. 
	The format is a number follwed by the one of the following units: "ops", "s",
	or "ms". If the specified value is less than 10s, the mirror is configured to 
	run in a fully synchronous mode. If the specified value is greater than or 
	equal to 10s, the mirror is configured to run in semi-synchronous mode. This
	is a deprecated parameter. Use the sync-mode parameter instead to specify the 
	sync mode. 
.PARAMETER SyncMode
    This specfies whether the mirror should be configured in sync or in semi-sync 
	mode. Possible values are: "full_sync" and "semi_sync". If the user wants to 
	configure the mirror to run in fully synchronous mode, the user must specify 
	"full_sync" as the value for this parameter. If the user wants to configure 
	the mirror to run in semi-synchronous mode, the user must specify "semi_sync" 
	as the value of this parameter. If not specified, the mirror will be configured
	to run in full synchronous mode. This parameter overrides the deprecated 
	ops-throttle parameter. 
.PARAMETER Server
   	NaServer to query
.EXAMPLE
    Set-NaSnapMirrorSchedule -Destination netapp1:sm_vol1 -Source netapp2:vol1 -SyncMode semi_sync
    
    Establish a semi-sync snapmirror relationship between netapp1:vol1 and netapp2:vol1
.OUTPUTS
	NetApp.SDK.NaSnapMirrorSyncSchedule[]
.Link
	Get-NaSnapMirrorSyncSchedule
	Get-NaSnapMirror
	Set-NaSnapMirror
	Initialize-NaSnapMirror
	Update-NaSnapMirror
#> 
function Set-NaSnapMirrorSyncSchedule {
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="Low",DefaultParameterSetName="bymode")]
	param(
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="bymode")]
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byops")]
	[alias("volume","Name")]
	[string]
	$Destination,

	[Parameter(Mandatory=$TRUE,Position=1,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="bymode")]
	[Parameter(Mandatory=$TRUE,Position=1,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byops")]
	[string]
	$Source,
	
	[Parameter(Mandatory=$TRUE,ParameterSetName="bymode")]
	[ValidateSet("full_sync","semi_sync")]
	[string]
	$SyncMode,

	[Parameter(Mandatory=$TRUE,ParameterSetName="byops")]
	[Validatepattern('(^\d+ops$)|(^\d+s$)|(^\d+ms$)')]
	[string]
	$OpsThrottle,
	
	[Parameter(ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="bymode")]
	[Parameter(ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="byops")]
	[int]
	$VisibilityFrequency = 180,

	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-set-sync-schedule")
		$request.AddNewChild("destination-location",$Destination)
		$request.AddNewChild("source-location",$Source)
		$request.AddNewChild("visibility-frequency",$VisibilityFrequency)
		switch ($PSCmdlet.ParameterSetName)
		{
			"byops" 
			{
				$request.AddNewChild("ops-throttle",$OpsThrottle)
				$msg = "Setting sync snapmirror from {1} to {2} updating every {0}" -f $OpsThrottle,$Source,$Destination
			}
			"bymode"
			{
				$request.AddNewChild("sync-mode",$SyncMode)
				$msg = "Setting {0} synchronous snapmirror from {1} to {2}" -f $SyncMode.split('_')[0],$Source,$Destination		
			}
		}
		if ($pscmdlet.ShouldProcess($Server.Server,$msg)){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
			if ($?){
				Get-NaSnapMirror -location $Destination -Server $Server
			}
		}
	}
}
<#
.SYNOPSIS
	Delete the synchronous schedule for a given destination. This cmdlet must be executed on the
    destination filer.
.DESCRIPTION
	Delete the synchronous schedule for a given destination. This cmdlet must be executed on the
    destination filer.
.PARAMETER Destination
	The destination location of a schedule to delete. The destination location is 
    of the volume form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>.
.PARAMETER Server
   	NaServer to query
.EXAMPLE
	Remove-NaSnapMirrorSyncSchedule -Destination Netapp1:vol1
.Link
	Get-NaSnapMirrorSyncSchedule
	Set-NaSnapMirrorSyncSchedule
	Initialize-NaSnapMirror
	Update-NaSnapMirror
	Restore-NaSnapMirror
#> 
function Remove-NaSnapMirrorSyncSchedule {
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="Low",DefaultParameterSetName="")]
	param(
		[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE)]
		[alias("volume")]
		[string]
		$Destination,
	
		[Parameter(HelpMessage="NaServer to query")]
		[NetApp.SDK.NaServer]
		$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-delete-sync-schedule")
		$request.AddNewChild("destination-location",$Destination)
		if ($pscmdlet.ShouldProcess($Server.Server, "Removing $($Destination) from the snapmirror Schedule")){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
		}
	}
}

<#
.SYNOPSIS
	Returns connection information for a given connection or all connections.
.DESCRIPTION
	Returns connection information for a given connection or all connections. This 
	cmdlet must be executed on the destination filer. Currently, the connections 
	are in: /etc/snapmirror.conf.
.PARAMETER Name
  	Connection name of the connection information to obtain. If the connections is 
	not specified, then the connection information for all the connections is returned
.PARAMETER Server
   	NaServer to query
.EXAMPLE
	Get-NaSnapMirrorConnections    
.OUTPUTS
	NetApp.SDK.NaSnapMirrorConnections[]
.notes
	KNOWS BUG IN API 1.9... work around 
	Invoke-NaExpression "rdfile /etc/snapmirror.conf" 
.Link
	Get-NaSnapmirror
	Set-NaSnapMirrorConnections
	Remove-NaSnapMirrorConnections
#> 
function Get-NaSnapMirrorConnections {
	[CmdletBinding(SupportsShouldProcess=$FALSE,SupportsTransactions=$False,ConfirmImpact="None",DefaultParameterSetName="")]
	param(
	[Parameter(Position=0,ValueFromPipelineByPropertyName=$TRUE)]
	[string]
	$Name,

	[Parameter(Position=1,HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-list-connections")
		if ($Name){
			$request.AddNewChild("connection",$Name)
		}
		try {
			$result = ([xml]$server.InvokeElem($request)).results
		}
		catch [NetApp.Manage.NaApiFailedException]{
			Write-Warning $_.Exception.GetBaseException().message
			$result = $null
			continue;
		}
		if ($?) {
			$result."snapmirror-connections"."connection-info" |
			Where-Object {$_."address-pair1"} | % {
				$AddressPair1 = $_."address-pair1"."address-pair" | % {
					New-Object NetApp.SDK.NaAddressPair -ArgumentList @(
					$_."source-addr",
					$_."destination-addr"
					)
				}
				$AddressPair2 = $_."address-pair2"."address-pair" | % {
					New-Object NetApp.SDK.NaAddressPair -ArgumentList @(
					$_."source-addr",
					$_."destination-addr"
					)
				}
				return New-Object NetApp.SDK.NaSnapMirrorConnection -ArgumentList @(
				$_."name",
				$AddressPair1,
				$AddressPair2
				$_."mode",
				@{"Errno"=$_.errno;"reason"=$_."reason"}
				)
			}
		}
	}
}
<#
.SYNOPSIS
	Sets up a connection. Set-NaSnapMirrorConnections will add a new connection or 
	modify an existing one. This cmdlet must be executed on the destination filer.
	Currently, the connections are in: /etc/snapmirror.conf.
.DESCRIPTION
	Sets up a connection. Set-NaSnapMirrorConnections will add a new connection or 
	modify an existing one. This cmdlet must be executed on the destination filer.
.PARAMETER Name
  	Name of the connection to add or modify. The name is in ASCII and must begin 
	with an alpha character
.PARAMETER AddressPair1
	The connection's first source and destination address pair. In multi mode, the 
	first address pair provides a connection path; while in failover mode, the first
	address pair provides the prefer connection path. 
.PARAMETER AddressPair2
	The connection's second source and destination address pair. In multi mode the
	second address pair provides another connection path, while in failover mode, 
	the second address pair provides a connection path in case the first path fails. 
.PARAMETER Mode
	Possible mode values are "multi" or "failover". If not specified, the default 
	is "multi". 
.PARAMETER Server
   	NaServer to query
.EXAMPLE
  	Set-NaSnapMirrorConnections -Name netapp2_netapp1 -AddressPair1 "192.168.1.12,192.168.1.11" `
	-AddressPair2 "192.168.2.12,192.168.2.11" -Mode failover
	
	Forces all snapmirror traffice over the 92.168.1.x network, using the 192.168.2.x as a backup.

.OUTPUTS
	NetApp.SDK.NaSnapMirrorConnections[]
.Link
	Get-NaSnapmirror
	Get-NaSnapMirrorConnections
	Remove-NaSnapMirrorConnections
#> 
function Set-NaSnapMirrorConnections {
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="low",DefaultParameterSetName="Single")]
	param(
	[Parameter(Mandatory=$True,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="Single")]
	[Parameter(Mandatory=$True,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="multi")]
	[string]
	$Name,

	[Parameter(Mandatory=$True,Position=1,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="Single")]
	[Parameter(Mandatory=$True,Position=1,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="multi")]
	[string]
	$AddressPair1,

	[Parameter(Mandatory=$True,Position=2,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="multi")]
	[string]
	$AddressPair2,

	[Parameter(Position=3,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="multi")]
	[ValidateSet("multi", "failover")]
	[string]
	$Mode, 

	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-set-connection")
		$request.AddNewChild("connection",$Name)
		$ap1 = New-Object NetApp.Manage.NaElement("address-pair1")
		$ap1.AddChildElement($AddressPair1.tonaelement())
		$request.AddChildElement($ap1)
		if ($AddressPair2) {
			$ap2 = New-Object NetApp.Manage.NaElement("address-pair2")
			$ap2.AddChildElement($AddressPair2.tonaelement())
			$request.AddChildElement($ap2)
		}
		if ($Mode) {
			$request.AddNewChild("mode",$Mode.ToLower())
		}
		if ($pscmdlet.ShouldProcess($Server.Server,"Setting SnapMirror connection for $($name)")){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
			if ($?) {
				Get-NaSnapMirrorConnections -Name $Name -Server $Server
			}
		}
	}
}
<#
.SYNOPSIS
	Deletes a connection specified by connection name.  This cmdlet must be executed 
	on the destination filer. Currently, the connections are in: /etc/snapmirror.conf.
.DESCRIPTION
	Deletes a connection specified by connection name.  This cmdlet must be executed 
	on the destination filer. Currently, the connections are in: /etc/snapmirror.conf.
.PARAMETER Name
  	Name of the connection to delete.
.PARAMETER Server
   	NaServer to query
.EXAMPLE
  	Remove-NaSnapMirrorConnections -Name netapp2_netapp1
.Link
	Get-NaSnapMirrorConnections
	Set-NaSnapMirrorConnections
#> 
function Remove-NaSnapMirrorConnections {
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="low",DefaultParameterSetName="")]
	param(
	[Parameter(Mandatory=$True,Position=0,ValueFromPipelineByPropertyName=$TRUE)]
	[string]
	$Name,

	[Parameter(HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-delete-connection")
		$request.AddNewChild("connection",$Name)
		if ($pscmdlet.ShouldProcess($Server.Server,"removing SnapMirror connection $($name)")){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
		}
	}
}

<#
.SYNOPSIS
	Returns a list of destination locations and information about SnapMirror relationships
	for given source locations, which can be a volume name or qtree path. This cmdlet must 
	be issued on the source filer. 
.DESCRIPTION
	Returns a list of destination locations and information about SnapMirror relationships
	for given source locations, which can be a volume name or qtree path. 
.PARAMETER Name
  	Source location of the SnapMirror pair. The source location is of the volume 
	form: <filer>:<volume> or the qtree form: <filer>:/vol/<volume>/<qtree>. If the 
	source location is not specified, then all source, destination SnapMirror pairs are 
	returned. 
.PARAMETER Server
   	NaServer to query
.EXAMPLE
  	Get-Navol | Get-NaSnapMirrorDestination   
.OUTPUTS
	NetApp.SDK.NaSnapMirrorConnections[]
.Link
	Get-NaVol
	Get-NaSnapMirror
#> 
function Get-NaSnapMirrorDestination {
	[CmdletBinding(SupportsShouldProcess=$FALSE,SupportsTransactions=$False,ConfirmImpact="None",DefaultParameterSetName="")]
	param(
	[Parameter(Position=0,ValueFromPipelineByPropertyName=$TRUE)]
	[string]
	$Name,

	[Parameter(Position=1,HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-list-destinations")
		if ($Name){
			$request.AddNewChild("source-location",$Name)
		}
		try {
			$result = ([xml]$server.InvokeElem($request)).results
		}
		catch [NetApp.Manage.NaApiFailedException]{
			Write-Warning $_.Exception.GetBaseException().message
			$result = $null
			continue;
		}
		if ($?) {
			$result."destinations"."destination-info" |
			Where-Object {$_."destination-location"} | % {
				return New-Object NetApp.SDK.NaSnapMirrorDestination -ArgumentList @(
				$_."source-location",
				$_."destination-location",
				$_."source-snapshot"
				)
			}
		}
	}
}
<#
.SYNOPSIS
	 Test the SnapMirror status values for a given volume.
.DESCRIPTION
	 Test the SnapMirror status values for a given volume. When ran without any 
	 additional switches all status values are returned simultaneously.
.PARAMETER Name
  	Name of the volume to be queried. 
.PARAMETER Transfer
	When applied cmdlet will return true if a SnapMirror transfer as a destinaion 
	or source volume is currently in progress
.PARAMETER Broken
	When applied cmdlet will return True if a SnapMirror transfer state as a 
	destination volume has been stopped due the snapmirror break command or the 
	Set-NaSnapmirror -break cmdlet.
.PARAMETER Source
	When applied cmdlet will True if the volume is a SnapMirror source. 
.PARAMETER Destination
	When applied cmdlet will True if the volume is a SnapMirror destination. 
.PARAMETER Server
   	NaServer to query
.EXAMPLE
  	Get-NaVol | Test-NaVolSnapMirrorStatus
.Example
    Get-NaVol | ?{Test-NaVolSnapMirrorStatus -name $_.Name -Source}
	
	will return only the volumes that are snapmirror sources
.OUTPUTS
	NetApp.SDK.NaSnapMirrorConnections[]
.Link
	Get-NaVol
	Get-NaSnapmirror
#> 
function Test-NaVolSnapMirrorStatus {
	[CmdletBinding(SupportsShouldProcess=$FALSE,SupportsTransactions=$False,ConfirmImpact="None",DefaultParameterSetName="ALL")]
	param(
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="Transfer")]
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="Broken")]
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="Source")]
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="Destination")]
	[Parameter(Mandatory=$TRUE,Position=0,ValueFromPipelineByPropertyName=$TRUE,ParameterSetName="ALL")]
	[Alias("Volume")]
	[string]
	$Name,

	[Parameter(ParameterSetName="Transfer")]
	[switch]
	$Transfer,

	[Parameter(ParameterSetName="Broken")]
	[switch]
	$Broken,

	[Parameter(ParameterSetName="Source")]
	[switch]
	$Source,

	[Parameter(ParameterSetName="Destination")]
	[switch]
	$Destination,

	[Parameter(Position=1,HelpMessage="NaServer to query")]
	[NetApp.SDK.NaServer]
	$server = (Get-NaServer)
	)
	Process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("snapmirror-get-volume-status")
		if ($Name){
			$request.AddNewChild("volume",$Name)
		}
		try {
			$result = ([xml]$server.InvokeElem($request)).results
		}
		catch [NetApp.Manage.NaApiFailedException]{
			Write-Warning $_.Exception.GetBaseException().message
			$result = $null
			continue;
		}
		if ($?) {
			switch ($PSCmdlet.ParameterSetName)
			{
				"Transfer" 
				{
					return (ConvertFrom-NaBool $result."is-transfer-in-progress")
				}
				"broken" 
				{
					return (ConvertFrom-NaBool $result."is-transfer-broken")
				}
				"source" 
				{
					return (ConvertFrom-NaBool $result."is-source")
				}
				"destination" 
				{
					return (ConvertFrom-NaBool $result."is-destination")

				}
				"ALL" 
				{
					return New-Object NetApp.SDK.NaVolumeSnapMirrorStatus -ArgumentList @(
					$name,
					(ConvertFrom-NaBool $result."is-destination"),
					(ConvertFrom-NaBool $result."is-source"),
					(ConvertFrom-NaBool $result."is-transfer-broken"),
					(ConvertFrom-NaBool $result."is-transfer-in-progress")
					)
				}
			}
		}
	}
}
